package znet

import (
	"fmt"
	"net"
	"zinx/utils"
	"zinx/ziface"
)

// IService接口实现，定义一个Service的服务模块
type Service struct {

	// 服务器名称
	Name string
	// 服务器绑定的ip版本
	IPVersion string
	// 服务器监听的ip
	IP string
	// 服务器监听的端口
	Port int
	// 绑定msgId对应的处理逻辑
	MsgHandle ziface.IMsgHandle
	// 该server的链接管理器
	ConnManager ziface.IConnManager

	// 该Server 创建链接后自动调用HooK函数-- onConnStart
	OnConnStart func(conn ziface.IConnection)

	// 该Server 销毁链接前自动调用HooK函数 -- OnConnStop
	OnConnStop func(conn ziface.IConnection)
}

// 启动服务器方法
func (s *Service) Start() {
	fmt.Printf("[Zinx] Server Name:%s,Listenner at IP :%s ,Port %d, is starting\n",
		utils.GlobalObject.Name, utils.GlobalObject.Host, utils.GlobalObject.TcpPort)
	fmt.Printf("[Start] Server Listenner at IP :%s ,Port %d, is starting\n", s.IP, s.Port)

	// 异步处理链接
	go func() {
		// 0.开启消息队列及Worker工作池
		s.MsgHandle.StartWorkerPool()

		// 1.获取一个TCP的addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Println("resolve tcp addr error :", err)
			return
		}

		// 2.监听服务器的地址
		tcp, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Println("listen ", s.IPVersion, "err", err)
			return
		}
		fmt.Println("start Zinx server success", s.Name, "success ,Listenning..")

		var cid uint32
		cid = 0

		// 3. 阻塞的等待客户端连接，处理客户端连接业务（读写）
		for {
			conn, err := tcp.AcceptTCP()
			if err != nil {
				fmt.Println("Accept err", err)
				continue
			}

			// 判断链接个数是否已达上限
			if s.ConnManager.Len() >= utils.GlobalObject.MaxConn {
				// TODO 客户端响应一个超出最大链接的错误包
				conn.Close()
				continue
			}

			// TODO 已经与客户端建立连接，处理业务
			connection := NewConnection(s, conn, cid, s.MsgHandle)
			cid++

			// 启动当前的链接业务处理
			go connection.Start()
		}
	}()

}

// 停止服务器方法
func (s *Service) Stop() {

	// TODO 将一些服务器的资源、状态或者一些已经开辟的链接信息进行停止或回收

	fmt.Println("[STOP] Zinx server name", s.Name)
	s.ConnManager.ClearConn()
}

// 运行服务器方法
func (s *Service) Serve() {
	// 启动server的服务功能
	s.Start()

	// TODO 做一些启动服务器之后的额外功能

	// 阻塞状态
	select {}

}

// 添加路由方法
func (s *Service) AddRouter(msgID uint32, router ziface.IRouter) {
	s.MsgHandle.AddRouter(msgID, router)
}

func (s *Service) GetConnManager() ziface.IConnManager {
	return s.ConnManager
}

// 初始化Server模块方法
func NewServer(name string) ziface.IService {
	s := &Service{
		Name:        utils.GlobalObject.Name,
		IPVersion:   "tcp4",
		IP:          utils.GlobalObject.Host,
		Port:        utils.GlobalObject.TcpPort,
		MsgHandle:   NewMsgHandle(),
		ConnManager: NewConnManager(),
	}
	return s
}

// 注册OnConnStart 钩子函数的方法
func (s *Service) SetOnConnStart(hookFun func(connection ziface.IConnection)) {
	s.OnConnStart = hookFun
}

// 注册OnConnStop 钩子函数的方法
func (s *Service) SetOnConnStop(hookFun func(connection ziface.IConnection)) {
	s.OnConnStop = hookFun
}

// 调用 OnConnStart 钩子函数方法
func (s *Service) CallOnConnStart(connection ziface.IConnection) {
	if s.OnConnStart != nil {
		fmt.Println("--->Call OnConnStart()....")
		s.OnConnStart(connection)
	}
}

// 调用OnConnStop 钩子函数方法
func (s *Service) CallOnConnSop(connection ziface.IConnection) {
	if s.OnConnStop != nil {
		fmt.Println("--->Call OnConnStop()....")
		s.OnConnStop(connection)
	}
}
